var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                                 .getService(Components.interfaces.nsIWindowMediator);
var gl_alpha1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var gl_alpha2 = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
var gl_alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
var gl_alnumb = new Array();
for (var revTableIdx = 0; revTableIdx < 64; ++revTableIdx) {
  gl_alnumb[gl_alnum[revTableIdx]] = revTableIdx;
}
function gl_str_rot13(str) {
	var newStr = "";
	var curLet, curLetLoc;
	for (var i = 0; i < str.length; i++) {
		curLet = str.charAt(i);
		curLetLoc = gl_alpha1.indexOf(curLet);
		newStr += (curLetLoc < 0) ? curLet : gl_alpha2.charAt(curLetLoc);
	}
	return newStr;
}
function gl_str_rot13_back(str) {
	var newStr = "";
	var curLet, curLetLoc;
	for (var i = 0; i < str.length; i++) {
		curLet = str.charAt(i);
		curLetLoc = gl_alpha2.indexOf(curLet);
		newStr += (curLetLoc < 0) ? curLet : gl_alpha1.charAt(curLetLoc);
	}
	return newStr;
}
function gl_trim(string) {
	return string.replace(/(^\s+)|(\s+$)/g, "");
}
function gl_base64_encode(str) {
	var out = "";
	var t, x, y, z;
	for (var i = 0; i < str.length; i += 3) {
		t = Math.min(3, str.length - i);
		if (t == 1) {
			x = str.charCodeAt(i);
			out += gl_alnum.charAt((x >> 2));
			out += gl_alnum.charAt(((x & 3) << 4));
			out += "--";
		} else {
			if (t == 2) {
				x = str.charCodeAt(i);
				y = str.charCodeAt(i + 1);
				out += gl_alnum.charAt((x >> 2));
				out += gl_alnum.charAt((((x & 3) << 4) | (y >> 4)));
				out += gl_alnum.charAt(((y & 15) << 2));
				out += "-";
			} else {
				x = str.charCodeAt(i);
				y = str.charCodeAt(i + 1);
				z = str.charCodeAt(i + 2);
				out += gl_alnum.charAt((x >> 2));
				out += gl_alnum.charAt((((x & 3) << 4) | (y >> 4)));
				out += gl_alnum.charAt((((y & 15) << 2) | (z >> 6)));
				out += gl_alnum.charAt((z & 63));
			}
		}
	}
	return out;
}
function gl_base64_decode(str) {
  var source = str;
  var counter = 0;

  if (str == null || str.length == 0) {
    return "";
  }

  // We'll build up the result string in this varable.
  var ret = "";

  var chunk = gl_getNextChunk(source, counter);
  counter += 4;
  while (chunk.length > 0) {
    // Convert the (up to) four 6 bits-per-byte chunk elements into (up to)
    // three 8 bits-per-byte resulting decoded characters.
    ret += String.fromCharCode((chunk[0] << 2) & 0xff | (chunk[1] >> 4) & 0x3f);
    if (chunk.length > 2) {
      ret += String.fromCharCode((chunk[1] << 4) & 0xff | (chunk[2] >> 2) & 0x3f);
      if (chunk.length > 3) {
        ret += String.fromCharCode((chunk[2] << 6) & 0xff | chunk[3]);
      }
    }

    chunk = gl_getNextChunk(source, counter);
    counter += 4;
  }

  return ret;
}
function gl_getNextChunk(source, counter) {
  var chunk = new Array();

  for (var x = 0; x < 4; ++x) {
    if (counter < source.length) {
      var c = source.charAt(counter);
      if (c != '-') {
        chunk[x] = gl_alnumb[c];
      }
      ++counter;
    }
  }

  return chunk;
}
function gl_parseSite(url){
	if (!/^http\:\/\//.test(url)){
		return "";
	}
	return url.replace(/^http\:\/\/([^\/\:]*).*/, "$1");
}
function gl_isErrorPage(url){
	if (typeof(url) == "undefined" || url == null){
		return [false, null];
	}
	var errorPage = false;
	if (url.substring(0, 14) == "about:neterror") {
		var re = new RegExp("&u=([^&]*)");
		var arr;
		if ((arr = re.exec(url)) !== undefined) {
			url = arr[1];
		}
		url = unescape(url);
		errorPage = true;
	}
	return [errorPage, url];
}

function gl_ddump(str) {
	dump(str + "\n");
}
function gl_ddumpObject(obj, name, maxDepth, curDepth) {
	if (curDepth == undefined) {
		curDepth = 0;
	}
	if (maxDepth != undefined && curDepth > maxDepth) {
		return;
	}
	var i = 0;
	for (prop in obj) {
		i++;
		if (typeof (obj[prop]) == "object") {
			if (obj[prop] && obj[prop].length != undefined) {
				gl_ddump(name + "." + prop + "=[probably array, length " + obj[prop].length + "]");
			} else {
				gl_ddump(name + "." + prop + "=[" + typeof (obj[prop]) + "]");
			}
			gl_ddumpObject(obj[prop], name + "." + prop, maxDepth, curDepth + 1);
		} else {
			if (typeof (obj[prop]) == "function") {
				gl_ddump(name + "." + prop + "=[function]");
			} else {
				gl_ddump(name + "." + prop + "=" + obj[prop]);
			}
		}
	}
	if (!i) {
		gl_ddump(name + " is empty");
	}
}
//function fgladder(e) {
//	if (gGladder._enabled && gGladder.is_tbird) {
//		if (e.originalTarget instanceof HTMLDocument) {
//			var doc = e.originalTarget;
//			gGladder.adapt(doc);
//		}
//	}
//}
function gl_adapter(str) {
	this._str = str;
	try{
		this._decode = false;
		this._type = 0;
		if (str.charAt(0) == '#'){
			str = str.substr(1);
			this._premodify = (str.charAt(0) == '?');
			if (this._premodify){
				str = str.substr(1);
			}
			if (str.charAt(0) == "%"){
				this._decode = true;
				str = str.substr(1);
			}
			else{
				this._type = parseInt(str.substr(0, 2));
				if (isNaN(this._type)){
					this._err = true;
					return;
				}
				str = str.substr(2);
			}
		}
		var coupe = str.split("\n");
		if (coupe.length < 2) {
			this._err = true;
			return;
		}
		this._src = coupe[0];
		this._dst = coupe[1];
		this._default = false;
		this._name = (coupe.length > 2)?coupe[2]:"";
		this._toDefault = /^>\=/.test(this._name);
		if (this._toDefault){
			this._name = this._name.substr(2);
		}
		if (this._dst.charAt(0) == ">") {
			this._dst = this._dst.substr(1);
			if (this._dst.charAt(0) == "="){
				this._default = true;
				this._dst = this._dst.substr(1);
				if (this._name.length == 0){
					this._name = gl_parseSite(this._dst);
				}
			}
		}
		this._err = false;
		this._re = new RegExp(this._src, "i");
	}
	catch(e){
		gl_ddump(e.message);
		this._err = true;
	}
}
gl_adapter.prototype.toString = function () {
//	var str = this.getGrammarString();
//	if (this._name.length>0){
//		str += ((this._toDefault)?"\n>=":"\n")+this._name;
//	}
	return this._str;
};
//gl_adapter.prototype.getGrammarString = function(){
//	var defFlag = (this._default)? ">=": "";
//	if (this._decode){
//		return "#%" + this._src + "\n"+ defFlag + this._dst;
//	}
//	else if (this._type == 0){
//		return this._src + "\n"+ defFlag + this._dst;
//	}
//	else{
//		return "#"+this._type+this._src + "\n"+ defFlag + this._dst;
//	}
//};
gl_adapter.prototype.process = function(url ,callback){
	if (!this._err && (this._default || this._re.test(url))) {
		if (this._toDefault){
			var ada = gGladder._defaultAda;
			if (this._type != ada._type){
				for (var i=0; i<gGladder._defaultAdaList.length; i++){
					if (this._type == gGladder._defaultAdaList[i]._type){
						ada = gGladder._defaultAdaList[i];
						break;
					}
				}
			}
			ada.process(url, callback);
		}
		else{
			callback(this.processUrl(url));
		}
		return true;
	}
	return false;
};
gl_adapter.prototype.processUrl = function(url){
	switch(this._type){
	case 0:
		if (this._decode){
			var ret = this._dst;
			var res = this._re.exec(url);
//			gl_ddump("url:"+url);
//			gl_ddumpObject(res, "res", 1);
			for (var i=res.length ; i>0; i--){
				var re = new RegExp("\\$"+i, "g");
				ret = ret.replace(re, decodeURIComponent(res[i]));
			}
//			gl_ddump("ret:"+ret);
			return (ret);
		}
		else{
			return url.replace(this._re, this._dst);
		}
	case 1:
		return this._dst + url;
	case 13:
		return this._dst+encodeURIComponent(gl_str_rot13(url));
	case 64:
		return this._dst+gl_base64_encode(url);
	}
}
function gl_progressListener() {
}
gl_progressListener.prototype.QueryInterface = function () {
	if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
	    aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
	    aIID.equals(Components.interfaces.nsISupports))
	  return this;
	throw Components.results.NS_NOINTERFACE;
};
function Gladder(observe) {
	if (typeof(observe) == "undefined"){
		observe = true;
	}
	this._updateIndex = 0;
	this._adapters = new Array;
	this._sites = new Array;
	this._urls = new Array;
	this._namePrefEnabled = "gladder.enabled";
	this._namePrefAdapters = "gladder.adapters";
	this._namePrefUpdateURL = "gladder.updateurl";
	this._namePrefUpdateTimeout = "gladder.updatetimeout";
	this._namePrefSites = "gladder.sites";
	this._namePrefUnproxy = "gladder.unproxy";
	this._namePrefProxyUrl = "gladder.proxy.url";
	this._namePrefProxyType = "gladder.proxy.type";
	this._namePrefWorkWithNetworkProxy = "gladder.workwithnetworkproxy";
	this._namePrefDefaultAdapterName = "gladder.defaultadaptername";
	this._nameStatusImg = "gladderStatusImage";
	this._nameStringTooltipTrack = "tooltip.track";
	this._nameStringStatusEnable = "status.tooltip.enabled";
	this._nameStringStatusDisabledByProxy = "status.tooltip.disabledbyproxy";
	this._nameStringStatusDisable = "status.tooltip.disabled";
	this._nameStringStatusProxy = "menu.label.proxy";
	this._nameStringStatusUnproxy = "menu.label.unproxy";
	this._pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
	this._enabled = true;
	this._unproxy = true;
	this._workWithNetworkProxy = false;
	this._defaultAda = null;
	this._defaultAdaList = new Array;
	this._timeout = 3600000;
	this.NAME_ADA_CUSTOM = "custom proxy";
	if (observe){
    var observerService = Components.
      classes["@mozilla.org/observer-service;1"].
      getService(Components.interfaces.nsIObserverService);

    observerService.addObserver(this, "gl_loadpref", false);	
	}
//	this._currentUrl = null;
}
Gladder.prototype.observe = function(aSubject, aTopic, aData){
	if (aTopic == "gl_loadpref"){
		this.loadPref();
	}
};
Gladder.prototype.QueryInterface = function(aIID){
  if (!aIID.equals(Components.interfaces.nsIObserver) &&
      !aIID.equals(Components.interfaces.nsISupports))
    throw Components.results.NS_ERROR_NO_INTERFACE;
   return this;
};
Gladder.prototype.notify = function(){
	Components.classes['@mozilla.org/observer-service;1'].getService(Components.interfaces.nsIObserverService).notifyObservers(null, 'gl_loadpref', '');
};
//hacked from IeTab
Gladder.prototype.hookCode = function(orgFunc, orgCode, myCode) {
   if (orgFunc == "") return;
   switch (orgCode) {
   case "{":
      orgCode = /{/;
      myCode = "{"+myCode;
      break;
   case "}":
      orgCode = /}$/;
      myCode = myCode+"}";
      break;
   default:
   }
   try { eval(orgFunc + "=" + eval(orgFunc).toString().replace(orgCode, myCode)); }catch(e){ gl_ddump("Failed to hook function: "+orgFunc); }
//   gl_ddump(eval(orgFunc).toString());
};
//hacked from IeTab
Gladder.prototype.hookProp = function(parentNode, propName, myGetter, mySetter) {
   var oGetter = parentNode.__lookupGetter__(propName);
   var oSetter = parentNode.__lookupSetter__(propName);
   if (oGetter && myGetter) myGetter = oGetter.toString().replace(/{/, "{"+myGetter.toString().replace(/^.*{/,"").replace(/.*}$/,""));
   if (oSetter && mySetter) mySetter = oSetter.toString().replace(/{/, "{"+mySetter.toString().replace(/^.*{/,"").replace(/.*}$/,""));
   if (!myGetter) myGetter = oGetter;
   if (!mySetter) mySetter = oSetter;
   if (myGetter) try { eval('parentNode.__defineGetter__(propName, '+ myGetter.toString() +');'); }catch(e){ gl_ddump("Failed to hook property Getter: "+propName); }
   if (mySetter) try { eval('parentNode.__defineSetter__(propName, '+ mySetter.toString() +');'); }catch(e){ gl_ddump("Failed to hook property Setter: "+propName); }
};
Gladder.prototype.hookCodeAll = function() {
//   this.hookCode('gBrowser.mTabProgressListener', "function (aWebProgress, aRequest, aLocation) {", "$& gGladder.checkFilter(this.mBrowser, aRequest, aLocation);");
   this.hookCode('gBrowser.mTabProgressListener', "function (aWebProgress, aRequest, aStateFlags, aStatus) {", "$& gGladder.stateChange(this.mBrowser, aWebProgress, aRequest, aStateFlags, aStatus);");
   for(var i=0 ; i<gBrowser.mTabListeners.length ; i++){
//      this.hookCode("gBrowser.mTabListeners["+i+"].onLocationChange", "{", "gGladder.checkFilter(this.mBrowser, aRequest, aLocation);");
      this.hookCode("gBrowser.mTabListeners["+i+"].onStateChange", "{", "gGladder.stateChange(this.mBrowser, aWebProgress, aRequest, aStateFlags, aStatus);");
   }
   this.hookCode("BrowserLoadURL", /\S+\.value/, "gGladder.filterInput($&)");
   this.hookCode("getShortcutOrURI", /return (\S+);/, "return gGladder.filterInput($1);");
};
Gladder.prototype.stateChange = function(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus){
	var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
	var nsIChannel = Components.interfaces.nsIChannel;
	if (aStateFlags & nsIWebProgressListener.STATE_START){
		try{
			var url = aRequest.QueryInterface(nsIChannel).URI.spec;
			aWebProgress.DOMWindow.gl_url = url;
			var rp = gGladder.filterUrl(url);
			if (rp != url){
			    aRequest.cancel(0x804b0002); //NS_BINDING_ABORTED
			    aBrowser.loadURI(rp);
			}
		}catch(e){}
	}
};
Gladder.prototype.shouldProxy = function(){
	return this._enabled && (!this.usingNetworkProxy() || this._workWithNetworkProxy);
};
Gladder.prototype.filterInput = function(_url){
	var url = _url;
		if (!/^\w+\:\/\//.test(url)){
			url = "http://"+url;
		}
		if (/^http\:\/\/[^\/]+$/.test(url)){
			url += "/";
		}
	var furl = this.filterUrl(url);
	if (url != furl){
		return furl;
	}
	else{
		return _url;
	}
};
Gladder.prototype.filterUrl = function(url){
	if (this.shouldProxy()){
		return this.checkUrl(url);
	}
	return url;
};
Gladder.prototype.checkUrl = function(url){
	var _url = url;
	var arr = this.checkAdapters(url);
	_url = arr[1];
	if (arr[0]){
		return arr[1];
	}
	else if (this.isSite(gl_parseSite(_url))[0] && this._defaultAda !== null){
		this._defaultAda.process(_url, function(rp){url = rp});
	}
	return url;
};
Gladder.prototype.checkAdapters = function(url){
	var modified = false;
	for (var j = 0; j < this._adapters.length; j += 1) {
		var ada = this._adapters[j];
		if (ada.process(url, function(rp){url = rp;})){
			if (!ada._premodify)
				modified = true;
		}
	}
	return [modified, url];
};
Gladder.prototype.getCurrentUrl = function(){
	if(typeof(content.gl_url) == "undefined" || content.gl_url == null){
		content.gl_url = content.document.URL;
	}
	return gl_isErrorPage(content.gl_url)[1];
};
Gladder.prototype.usingNetworkProxy = function(){
	return this._pref.getIntPref("network.proxy.type") > 0;
};
Gladder.prototype.adapt = function (doc) {
	var allLinks = doc.links;
	for (var j = 0; j < this._adapters.length; j += 1) {
		var ada = this._adapters[j];
		for (var i = 0; i < allLinks.length; i += 1) {
			ada.process(allLinks[i].href, callback);
		}
	}
	function callback(url){
		allLinks[i].href = url;
		var title = allLinks[i].getAttribute("title");
		if (title) {
			title += " (" + gGladder.getString(gGladder._nameStringTooltipTrack) + ")";
		} else {
			title = gGladder.getString(gGladder._nameStringTooltipTrack);
		}
		allLinks[i].setAttribute("title", title);
	}
};
Gladder.prototype.redirect = function (url, wnd) {
	var modified = false;
	for (var j = 0; j < this._adapters.length; j += 1) {
		var ada = this._adapters[j];
		if (ada.process(url, function(rp){url = rp;})){
			modified = true;
		}
	}
	if (modified){
		try{
			wnd.location.replace(url);
		}
		catch(e){};
	}
	return modified;
};
Gladder.prototype.check = function(url, wnd){
	if (!this.redirect(url, wnd)) {
		if (this.isSite(gl_parseSite(url))[0]){
			this.defaultAda(url, wnd);
		}
	}
};
Gladder.prototype.keepCheckingProxy = function(){
	gGladder.updateStatus();
	setTimeout(gGladder.keepCheckingProxy, 100);
};
Gladder.prototype.proxyed = function(){
	var url = this.getCurrentUrl();
	return gl_parseSite(url) != this.getCurrentSite();
};
Gladder.prototype.unproxyThis = function(){
	this.enable(false);
	content.document.location.replace(this.getOriginalUrl(this.getCurrentUrl()));
};
Gladder.prototype.defaultAda = function (url, wnd){
	if (this._defaultAda !== null){
		this._defaultAda.process(url, function(url){
			try{
				wnd.location.replace(url);
			}catch(e){}
			});
	}
};
Gladder.prototype.getString = function (name) {
	if (!this._stringBundle) {
		this._stringBundle = document.getElementById("gladderstrings");
	}
	return this._stringBundle.getString(name);
};
Gladder.prototype.selectProxy = function(name){
	var cus=(name==this.NAME_ADA_CUSTOM);
	document.getElementById('proxyurl').disabled = !cus;
	document.getElementById('proxytype').disabled = !cus;
	if (!cus && this._pref.getCharPref(this._namePrefProxyUrl) == 0){
		var ada = this.findAda(name);
		if (ada != null){
			document.getElementById('proxyurl').value = ada._dst;
			document.getElementById('proxytype').selectedItem = document.getElementById('type'+(ada._type==1?"01":ada._type));
		}
	}
};
Gladder.prototype.initOptions = function(){
	this.loadPref(true);
	document.getElementById("autoredirect").checked = this._enabled;
	document.getElementById("workwithnetworkproxy").checked = this._workWithNetworkProxy;
	document.getElementById("unproxy").checked = this._unproxy;
	document.getElementById("sites").setAttribute("value", this._pref.getCharPref(this._namePrefSites));
	document.getElementById("adapters").setAttribute("value", this._pref.getCharPref(this._namePrefAdapters));
	document.getElementById("proxyurl").setAttribute("value", this._pref.getCharPref(this._namePrefProxyUrl));
	document.getElementById("proxytype").selectedItem = document.getElementById('type'+this._pref.getCharPref(this._namePrefProxyType));
	var menu = document.getElementById('defaultadalist');
	var popup = document.getElementById('defaultadalistpopup');
	if (this._defaultAdaList.length > 0){
		var cus = popup.firstChild;
		for(var i=0; i<this._defaultAdaList.length; i++){
			var name = this._defaultAdaList[i]._name;
			var item = document.createElement('menuitem');
			item.setAttribute("value", name);
			item.setAttribute("label", name);
			item.setAttribute("id", name);
			popup.insertBefore(item, cus);
			if (this._defaultAda._name == name){
				menu.selectedIndex = i;
				this.selectProxy(name);
			}
		}
	}
	else{
//		var item = document.createElement('menuitem');
//		item.setAttribute("label", "undefined");
//		popup.appendChild(item);
//		menu.selectedIndex = 0;
		menu.setAttribute("disabled", true);
	}
};
Gladder.prototype.saveOptions = function(){
	this._pref.setCharPref(this._namePrefSites, document.getElementById("sites").value);
	this._pref.setBoolPref(this._namePrefEnabled, document.getElementById("autoredirect").checked);	
	this._pref.setBoolPref(this._namePrefUnproxy, document.getElementById("unproxy").checked);	
	this._pref.setBoolPref(this._namePrefWorkWithNetworkProxy, document.getElementById("workwithnetworkproxy").checked);
	var ada = document.getElementById('defaultadalist').value;
	this._pref.setCharPref(this._namePrefDefaultAdapterName, ada);
	if (ada == this.NAME_ADA_CUSTOM){
		this._pref.setCharPref(this._namePrefProxyUrl, document.getElementById("proxyurl").value);
		this._pref.setCharPref(this._namePrefProxyType, document.getElementById("proxytype").value);
	}
	this.notify();
};
Gladder.prototype.doLoad = function () {
	gGladder.keepCheckingProxy();
	gGladder.loadPref(true);
	gGladder.update();
	gGladder.hookCodeAll();
	document.getElementById("contentAreaContextMenu").addEventListener("popupshowing", gGladder.contextMenuPopup, false);
};
Gladder.prototype.doDOMContentLoaded = function (event) {
	if (gGladder._enabled && gGladder._unproxy){
		var doc = content.document;
		if (event.originalTarget instanceof HTMLDocument) {
			doc = event.originalTarget;
		}
		if (gGladder.isOnProxy(doc.location.href)){
			gGladder.recoverLinks(doc);
		}
	}
};
Gladder.prototype.recoverLinks = function (doc) {
	var allLinks = doc.links;
	for (var i = 0; i < allLinks.length; i += 1) {
		if (allLinks[i].href.indexOf(doc.location.href) == 0)
			continue;
		try{
			allLinks[i].href=gGladder.getOriginalUrl(allLinks[i].href);
		}
		catch(e){gl_ddump();}
	}
};
Gladder.prototype.update = function () {
	setTimeout(function () {
		gGladder.update();
	}, this._timeout);
	var update = this._pref.getCharPref(this._namePrefUpdateURL);
	var list = update.split("\n");
	if (this._updateIndex >= list.length) {
		this._updateIndex = 0;
	}
	try {
		var xmlhttp = new XMLHttpRequest();
//		gl_ddump("gladder update from: "+list[this._updateIndex]);
		xmlhttp.open("GET", list[this._updateIndex], true);
		xmlhttp.onreadystatechange = function () {
			try {
				if (xmlhttp.readyState == 4) {
					if (xmlhttp.status == 200) { //We actually want to catch bad pages
//						gl_ddump(xmlhttp.responseText);
						gGladder.processUpdate(xmlhttp.responseText);
					} else {
						gGladder._updateIndex += 1;
						gGladder.update();
					}
				}
			}
			catch (e) {
				gl_ddump(e);
				gGladder._updateIndex += 1;
				gGladder.update();
				return;
			}
		};
		xmlhttp.setRequestHeader("Cache-Control", "no-cache");
		xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT");
		xmlhttp.send(null);
	}
	catch (e) {
		gl_ddump(e);
		return;
	}
};
Gladder.prototype.processUpdate = function (response) {
	if (response.length > 0 && response.indexOf('Config File for Gladder') != -1) {
		this.loadAdapters(response);
		var str = this._adapters.join("\n\n");
		for (var i=0; i<this._defaultAdaList.length; i++){
			str += "\n\n"+this._defaultAdaList[i].toString();
		}
		this._pref.setCharPref(this._namePrefAdapters, str);
	  var dlg = windowMediator.getMostRecentWindow("gladder:settings");
		if (dlg){
			dlg.document.getElementById('adapters').setAttribute('value', this._pref.getCharPref(this._namePrefAdapters));
		}
		this.notify();
	}
};
Gladder.prototype.loadPref = function(loadAda){
	this._timeout = this._pref.getIntPref(this._namePrefUpdateTimeout);
	this._enabled = this._pref.getBoolPref(this._namePrefEnabled);
	this._unproxy = this._pref.getBoolPref(this._namePrefUnproxy);
	this._workWithNetworkProxy = this._pref.getBoolPref(this._namePrefWorkWithNetworkProxy);
	this.loadAdapters(this._pref.getCharPref(this._namePrefAdapters), loadAda);

	this.loadSites(this._pref.getCharPref(this._namePrefSites));

	this.updateStatus();
};
Gladder.prototype.findAda = function(name){
	for (var i=0; i<this._defaultAdaList.length; i++){
		if (this._defaultAdaList[i]._name == name)
			return this._defaultAdaList[i];
	}
	if (this._defaultAdaList.length > 0)
		return this._defaultAdaList[0];
	else
		return null;
};
Gladder.prototype.testAdapters = function () {
	if (this._timerTestAda) {
		clearTimeout(this._timerTestAda);
		this._timerTestAda = null;
	}
	//retest ever 10 minutes
	this._timerTestAda = setTimeout(function(){gGladder.testAdapters();}, 600000);
	for(var index=0; index<this._defaultAdaList.length; index++) {
		this.testAda(this._defaultAdaList[index]);
	}
};
Gladder.prototype.testAda = function (ada) {
	try {
		var xmlhttp = new XMLHttpRequest();
	//		gl_ddump("gladder update from: "+list[this._updateIndex]);
		xmlhttp.open("GET", ada.processUrl("http://www.yahoo.com"), true);
		xmlhttp.onreadystatechange = function () {
			try {
				if (xmlhttp.readyState == 4) {
					if (xmlhttp.status == 200) {
						if (ada._startTest){
							ada._ping = "("+Math.round(((new Date())-ada._startTest)/1000)+"s)";
						}
					} else {
						ada._ping = "NaN";
					}
				}
			}
			catch (e) {
				ada._ping = "ERR";
			}
		};
		xmlhttp.setRequestHeader("Cache-Control", "no-cache");
		xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT");
		ada._startTest = new Date();
		xmlhttp.send(null);
	}
	catch (e) {}			
};
Gladder.prototype.loadAdapters = function (str, loadAda) {
	if (loadAda){
		var adas = str.split("\n\n");
		this._adapters = new Array;
		this._defaultAdaList = new Array;
		for (var i = 0; i < adas.length; i += 1) {
			if (adas[i].length > 0) {
				var ada = new gl_adapter(adas[i]);
				if (!ada._err) {
					if (ada._default){
						this._defaultAdaList.push(ada);
					}
					else{
						this._adapters.push(ada);
					}
				}
			}
		}
		this.testAdapters();
	}
	var adaName = this._pref.getCharPref(this._namePrefDefaultAdapterName);
	if (this.NAME_ADA_CUSTOM == adaName){
		var url = this._pref.getCharPref(this._namePrefProxyUrl);
		if (url.length > 0){
			this._defaultAda = new gl_adapter("#"+this._pref.getCharPref(this._namePrefProxyType)+"\n"+">="+url+"\n"+this.NAME_ADA_CUSTOM);
			if (!this._defaultAda._err){
				this.testAda(this._defaultAda);
				return;
			}
		}
	}
	if (this._defaultAdaList.length > 0){
		this._defaultAda = this.findAda(adaName);
		this._pref.setCharPref(this._namePrefDefaultAdapterName, this._defaultAda._name);
	}
};
Gladder.prototype.getOriginalUrl = function(_url){
	var ada = null;
	var onProxy = false;
	var url = _url;
	var site = gl_parseSite(_url);
	for (var i=-1; i< this._defaultAdaList.length; i++){
		ada = (i==-1?this._defaultAda:this._defaultAdaList[i]);
		if (ada == null){
			continue;
		}
		var dst = ada._dst;
		if (_url.indexOf(dst) == 0){
			url = _url.substr(dst.length);
			onProxy = true;
			break;
		}
		else if (site == gl_parseSite(dst)){
			if (dst.indexOf('&') != -1){
				var lastPara = ada._dst.replace(/.*\&([^\=]+)\=$/, "$1");
				var re = new RegExp(".*[\?\&]"+lastPara+"\=([^\&]+).*");
				if (re.test(_url)){
					url = _url.replace(re, "$1");
					onProxy = true;
					break;
				}
			}
		}
	}
	if (onProxy){
		switch(ada._type){
			case 13:
				return gl_str_rot13_back(decodeURIComponent(url));
			case 64:
				return gl_base64_decode(url);
			default:
				return url;
		}
	}
	return url;
};
Gladder.prototype.getCurrentSite = function(){
	return gl_parseSite(this.getOriginalUrl(this.getCurrentUrl()));
};
Gladder.prototype.isSite = function(site){
	if (typeof(site) == "undefined"){
		site = this.getCurrentSite();
	}
	if (typeof(site) == "undefined" || site == null || site.length == 0){
		return [false, site];
	}
	if (this._defaultAda !== null && site == gl_parseSite(this._defaultAda._dst)){
		return [false ,site];
	}
	for(var i=0; i<this._sites.length; i++){
		if (new RegExp("^([\\w-]*\\.)*"+this._sites[i].replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")+"$", "i").test(site)){
			return [true, this._sites[i]];
		}
	}
	return [false, site];
};
Gladder.prototype.registerSite = function(site){
	if (typeof(site) == "undefined"){
		site = this.getCurrentSite().replace(/^www\./i, '');
	}
	if (site === null || site.length == 0){
		return;
	}
	if (this._defaultAda !== null && site == gl_parseSite(this._defaultAda._dst)){
		return;
	}
	for(var i=0; i<this._sites.length; i++){
		if (this._sites[i] == site){
			//already exist, remove
			this._sites.splice(i, 1);
			this.saveSite();
			var url = this.getCurrentUrl();
			var ourl = this.getOriginalUrl(url);
			//if on a proxy, get back
			if (ourl != url){
				content.location.replace(ourl);
			}
			return;
		}
	}
	//not exist, add
	this._sites.push(site);
	this.saveSite();
	this.check(this.getCurrentUrl(), content);
};
Gladder.prototype.saveSite = function(){
	this._pref.setCharPref(this._namePrefSites, this._sites.join("\n"));
	this.notify();
};
Gladder.prototype.loadSites = function (str) {
	this._sites = gl_trim(str.replace(/\n\n+/g, '\n')).split('\n');
};
Gladder.prototype.setProxy = function(name){
	this._pref.setCharPref(this._namePrefDefaultAdapterName, name);
	this.notify();
};
Gladder.prototype.isOnProxy = function(url){
	if (typeof(url) == "undefined"){
		url = this.getCurrentUrl();
	}
	return url != this.getOriginalUrl(url);
};
Gladder.prototype.contextMenuPopup = function(event){
	if (!gContextMenu)
		return;
	document.getElementById('gladder-copyoriginalurl').hidden = true;
	if (gContextMenu.onLink){
		var link = gContextMenu.link.toString();
		var olink = gGladder.getOriginalUrl(link);
		if (olink != link){
			document.getElementById('gladder-copyoriginalurl').hidden = false;
			document.getElementById('gladder-copyoriginalurl').setAttribute('tooltiptext', olink);
		}
	}
};
Gladder.prototype.popupProxyMenu= function (menu) {
	while(menu.firstChild.nextSibling){
		menu.removeChild(menu.firstChild);
	}
	var cus = menu.firstChild;
	cus.setAttribute('checked', true);
	cus.setAttribute('hidden', this._pref.getCharPref(this._namePrefProxyUrl).length == 0);
	if (this.NAME_ADA_CUSTOM == this._pref.getCharPref(this._namePrefDefaultAdapterName) && this._defaultAda._ping){
		var lab = cus.getAttribute('label');
		cus.setAttribute('label', lab.replace(/ \-.*/, "") + " - " + this._defaultAda._ping);
	}
	for(var i=0; i<this._defaultAdaList.length; i++){
		var name = this._defaultAdaList[i]._name;
		var item = document.createElement('menuitem');
		if (this._defaultAdaList[i]._ping){
			item.setAttribute("label", name + " - " + this._defaultAdaList[i]._ping);
		}
		else{
			item.setAttribute("label", name);
		}
		item.setAttribute("value", name);
		item.setAttribute("oncommand", "gGladder.setProxy(this.value);")
		if (this._defaultAda._name == name){
			item.setAttribute('type', 'checkbox');
			item.setAttribute('checked', true);
			cus.setAttribute('checked', false);
		}
		menu.insertBefore(item, cus);
	}
	return true;
};
Gladder.prototype.popupMenu= function (menu) {
	var elements = {};
	  
	var menuProxies = document.getElementById('gl-status-proxies');
	menuProxies.setAttribute('hidden', this._defaultAdaList.length == 0);

	var list = menu.getElementsByTagName("menuitem");
	for (var i = 0; i < list.length; i++){
		elements[list[i].id] = list[i];
	}
	
	var url = this.getCurrentUrl();
	var ourl = this.getOriginalUrl(url);
	var site = gl_parseSite(ourl).replace(/^www\./i, '');
	elements['gl-status-unproxythis'].setAttribute('hidden', true);
	elements['gl-status-copyoriginalurl'].setAttribute('hidden', ourl == url);
	elements['gl-status-recoverlinks'].setAttribute('hidden', ourl == url);
	elements['gl-status-copyoriginalurl'].setAttribute('tooltiptext', ourl);
	elements['gl-status-site'].setAttribute('hidden', true);
	if (site.length > 0){
		var arr = this.isSite(site);
		elements['gl-status-site'].setAttribute('checked', arr[0]);
		site = arr[1];
		elements['gl-status-site'].setAttribute('value', site);
		elements['gl-status-site'].setAttribute('label', site);
		//if is a page of adapters work on
		if (this.redirect(ourl, null)){
			if (ourl != url){
				elements['gl-status-unproxythis'].setAttribute('hidden', false);
				elements['gl-status-unproxythis'].setAttribute('tooltiptext', ourl);
			}
		}
		else{
			elements['gl-status-site'].setAttribute('hidden', false);
		}
	}
  	
	elements['gl-status-enable'].setAttribute('checked', this._enabled);
	elements['gl-status-unproxy'].setAttribute('checked', this._unproxy);
	elements['gl-status-workwithnetworkproxy'].setAttribute('checked', this._workWithNetworkProxy);
	return true;
};
Gladder.prototype.copyOriginalUrl = function(){
	var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper );
	if (gContextMenu){
		clipboard.copyString(this.getOriginalUrl(gContextMenu.onLink?gContextMenu.link.toString():this.getCurrentUrl()));
	}
	else{
		clipboard.copyString(this.getOriginalUrl(this.getCurrentUrl()));
	}
};
Gladder.prototype.clickStatus = function (e) {
	if (e.button == 0) {
		if (this.usingNetworkProxy()){
			this.enable(true);
			this.workWithNetworkProxy();
		}
		else{
			this.enable();
		}
	} else {
		if (e.button == 1) {
			var url = this.getCurrentUrl();
			var ourl = this.getOriginalUrl(url);
			if (this.redirect(ourl,null)){
				if (ourl != url){
					this.unproxyThis();
				}
			}
			else{
				this.registerSite();
			}
//			this.proxyThis();
		}
	}
};
Gladder.prototype.updateStatus = function(){
	var img = document.getElementById(this._nameStatusImg);
	if (!img) return;
	if (this.usingNetworkProxy() && !this._workWithNetworkProxy){
		img.src = "chrome://gladder/skin/gladderG.png";
		img.setAttribute("tooltiptext", this.getString(this._nameStringStatusDisabledByProxy));
	}
	else	if (this._enabled){
		img.src = "chrome://gladder/skin/gladder.png";
		img.setAttribute("tooltiptext", this.getString(this._nameStringStatusEnable));
	}
	else {
		img.src = "chrome://gladder/skin/gladderD.png";
		img.setAttribute("tooltiptext", this.getString(this._nameStringStatusDisable));
	}
};
Gladder.prototype.enable = function(enabled){
	if (typeof(enabled) == "undefined"){
		this._enabled = !this._enabled;
	}
	else{
		this._enabled = enabled;
	}
	if (this._enabled){
		this.check(this.getCurrentUrl(), content);
	}
	this._pref.setBoolPref(this._namePrefEnabled, this._enabled);
	this.updateStatus();
	this.notify();
};
Gladder.prototype.workWithNetworkProxy = function(){
	this._workWithNetworkProxy = !this._workWithNetworkProxy;
	this._pref.setBoolPref(this._namePrefWorkWithNetworkProxy, this._workWithNetworkProxy);
	this.updateStatus();
	this.notify();
};
Gladder.prototype.unproxy = function(){
	this._unproxy = !this._unproxy;
	this._pref.setBoolPref(this._namePrefUnproxy, this._unproxy);
	this.notify();
};
Gladder.prototype.openOptions= function(){
  var dlg = windowMediator.getMostRecentWindow("gladder:settings");
  if (dlg){
  	dlg.focus();
  }
  else{
	  var browser = windowMediator.getMostRecentWindow("navigator:browser");
	  browser.openDialog("chrome://gladder/content/options.xul", "_blank", "chrome,centerscreen");
  }
};
Gladder.prototype.openPage = function(pageUrl){
	var windowService = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
	var currentWindow = windowService.getMostRecentWindow("navigator:browser");
	if (currentWindow) {
		try {
		  currentWindow.delayedOpenTab(pageUrl);
		} catch(e) { currentWindow.loadURI(pageUrl); }
	}
	else
		window.open(pageUrl);
};
